// Simple Hangman Program
// User gets five incorrect guesses
// Word chosen randomly from words.txt
// Inspiration from: https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html
// This assignment will introduce you to some fundamental syntax in Rust:
// - variable declaration
// - string manipulation
// - conditional statements
// - loops
// - vectors
// - files
// - user input
// We've tried to limit/hide Rust's quirks since we'll discuss those details
// more in depth in the coming lectures.
extern crate rand;
use rand::Rng;
use std::convert::TryInto;
use std::fs;
use std::io;
use std::io::Write;

const NUM_INCORRECT_GUESSES: u32 = 5;
const WORDS_PATH: &str = "words.txt";

fn pick_a_random_word() -> String {
    let file_string = fs::read_to_string(WORDS_PATH).expect("Unable to read file.");
    let words: Vec<&str> = file_string.split('\n').collect();
    String::from(words[rand::thread_rng().gen_range(0, words.len())].trim())
}

fn main() {
    let secret_word = pick_a_random_word();
    // Note: given what you know about Rust so far, it's easier to pull characters out of a
    // vector than it is to pull them out of a string. You can get the ith character of
    // secret_word by doing secret_word_chars[i].
    let secret_word_chars: Vec<char> = secret_word.chars().collect();
    // Uncomment for debugging:
    println!("random word: {}", secret_word);

    // Your code here! :)
    let mut guessing_word: String = std::iter::repeat("-").take(secret_word.len()).collect();
    let mut guessed_letters = String::new();
    let mut correct_guesses: i32 = 0;
    let mut error_guesses: u32 = 0;
    println!("Welcome to Guess the Word!");
    loop {
        println!("\nThe word so far is {}", guessing_word);
        println!(
            "You have guessed the following letters: {}",
            guessed_letters
        );
        println!(
            "You have {} guesses left",
            NUM_INCORRECT_GUESSES - error_guesses
        );
        print!("Please guess a letter: ");
        io::stdout().flush().expect("Unable to flush stdout");
        let mut guess = String::new();
        io::stdin()
            .read_line(&mut guess)
            .expect("Unable to read line");
        // println!("You guessed: {}", guess); // debugging
        if guess.len() < 1 {
            continue;
        }
        guessed_letters.push(guess.chars().nth(0).unwrap());
        let tmp = correct_guesses;
        for (i, (guess_char, secret_char)) in guess.chars().zip(secret_word.chars()).enumerate() {
            if guessing_word.chars().nth(i) == Some('-') && guess_char == secret_char {
                guessing_word.replace_range(i..=1, &guess_char.to_string());
                correct_guesses += 1;
                break;
            }
        }
        if tmp == correct_guesses {
            error_guesses += 1;
            println!("Sorry, that letter is not in the word");
            if error_guesses == NUM_INCORRECT_GUESSES {
                println!(
                    "\nSorry, you ran out of guesses!. The secret word was: {}",
                    secret_word
                );
            }
        }

        if correct_guesses == secret_word_chars.len() {
            println!(
                "Congratulations you guessed the secret word: {}!",
                guessing_word
            );
            break;
        }
    }
}
